package com.piece.module.generator.util;

import com.piece.core.framework.util.string.StringUtil;
import com.piece.core.framework.util.time.DateUtil;
import com.piece.module.generator.config.JsonSchemaGeneratorConfig;
import com.piece.module.generator.constants.GenConstants;
import com.piece.module.generator.model.GenTable;
import com.piece.module.generator.model.GenTableColumn;
import com.piece.module.generator.support.DefaultTypeInfoAnnotator;
import com.piece.module.generator.support.PrintCodeWriter;
import com.sun.codemodel.JCodeModel;
import org.apache.velocity.VelocityContext;
import org.jsonschema2pojo.*;
import org.jsonschema2pojo.rules.RuleFactory;

import java.io.File;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 代码生成器工具类
 */
public class GenUtil {

    /**
     * 获取模板信息
     */
    public static VelocityContext getVelocityContext(GenTable table) {
        String moduleName = table.getModuleName();
        String businessName = table.getBusinessName();
        String packageName = table.getPackageName();
        String className = table.getClassName();
        String tplCategory = table.getTplCategory();
        String functionName = table.getFunctionName();
        GenTableColumn keyColumn = null;
        List<GenTableColumn> columns = table.getColumns();
        if (columns.size() > 0) {
            List<GenTableColumn> temps = columns.stream().filter(column -> column.isPk()).collect(Collectors.toList());
            keyColumn = temps.size() > 0 ? temps.get(0) : null;
        }

        // java对象数据传递到模板文件vm
        VelocityContext velocityContext = new VelocityContext();
        velocityContext.put("tableName", table.getTableName());
        velocityContext.put("tableComment", replaceKeyword(table.getTableComment()));
        velocityContext.put("tplCategory", tplCategory);
        velocityContext.put("functionName", StringUtil.isNotEmpty(functionName) ? functionName : "【请填写功能名称】");
        velocityContext.put("ClassName", className);
        velocityContext.put("classname", StringUtil.uncapitalize(className));
        velocityContext.put("moduleName", moduleName);
        velocityContext.put("businessName", businessName);
        velocityContext.put("basePackage", getBasePackage(packageName));
        velocityContext.put("packageName", packageName);
        velocityContext.put("author", table.getFunctionAuthor());
        velocityContext.put("datetime", DateUtil.formatDate(new Date()));
        velocityContext.put("pkColumn", keyColumn);
        velocityContext.put("importList", getImportList(columns));
        velocityContext.put("permissionPrefix", getPermissionPrefix(moduleName, businessName));
        velocityContext.put("columns", columns);
        velocityContext.put("table", table);
        return velocityContext;
    }

    /**
     * 获取模板信息
     */
    public static List<String> getTemplates(String tplCategory) {
        List<String> templates = new ArrayList<>();
        templates.add("vm/java/Persistence.java.vm");
        templates.add("vm/java/Repository.java.vm");
        templates.add("vm/java/RepositoryImpl.java.vm");
        templates.add("vm/java/Service.java.vm");;
        templates.add("vm/java/Controller.java.vm");
        templates.add("vm/html/edit.html.vm");
        templates.add("vm/vue/form.vue.vm");

        if (GenConstants.TPL_CRUD.equals(tplCategory)) {
            templates.add("vm/html/index.html.vm");
            templates.add("vm/vue/index.vue.vm");
        } else if (GenConstants.TPL_TREE.equals(tplCategory)) {
            templates.add("vm/html/tree.html.vm");
            templates.add("vm/html/tree-table.html.vm");
            templates.add("vm/vue/tree.vue.vm");
            templates.add("vm/vue/treetable.vue.vm");
        }
        //templates.add("vm/sql/sql.vm");
        return templates;
    }

    /**
     * 表名转换成Java类名
     */
    public static String tableToJava(String tableName, String tablePrefix) {
        if (StringUtil.isNotBlank(tablePrefix)) {
            tableName = tableName.replaceFirst(tablePrefix, "");
        }
        return StringUtil.convertToCamelCase(tableName, true);
    }

    /**
     * 列名转换成Java属性名
     */
    public static String columnToJava(String columnName) {
        return StringUtil.convertToCamelCase(columnName);
    }

    /**
     * 获取数据库类型字段
     */
    public static String getDbType(String columnType) {
        if (StringUtil.indexOf(columnType, "(") > 0) {
            return StringUtil.substringBefore(columnType, "(");
        } else {
            return columnType;
        }
    }

    /**
     * 获取字段长度
     */
    public static Integer getColumnLength(String columnType) {
        if (StringUtil.indexOf(columnType, "(") > 0) {
            String length = StringUtil.substringBetween(columnType, "(", ")");
            return Integer.valueOf(length);
        } else {
            return 0;
        }
    }

    /**
     * 根据列类型获取导入包
     *
     * @param columns 列集合
     * @return 返回需要导入的包列表
     */
    public static HashSet<String> getImportList(List<GenTableColumn> columns) {
        HashSet<String> importList = new HashSet<>();
        for (GenTableColumn column : columns) {
            if (GenConstants.TYPE_DATE.equals(column.getJavaType())) {
                importList.add("java.util.Date");
            } else if (GenConstants.TYPE_BIGDECIMAL.equals(column.getJavaType())) {
                importList.add("java.math.BigDecimal");
            }
        }
        return importList;
    }

    /**
     * 获取权限前缀
     *
     * @param moduleName 模块名称
     * @param businessName 业务名称
     * @return 返回权限前缀
     */
    public static String getPermissionPrefix(String moduleName, String businessName) {
        return StringUtil.format("{}:{}", moduleName, businessName);

    }

    public static String getBasePackage(String packageName) {
        int lastIndex = packageName.lastIndexOf(".");
        return StringUtil.substring(packageName, 0, lastIndex);
    }

    /**
     * 获取模块名
     */
    public static String getModuleName(String packageName) {
        int lastIndex = packageName.lastIndexOf(".");
        int nameLength = packageName.length();
        return StringUtil.substring(packageName, lastIndex + 1, nameLength);
    }

    /**
     * 获取业务名
     */
    public static String getBusinessName(String tableName) {
        int lastIndex = tableName.lastIndexOf("_");
        int nameLength = tableName.length();
        String businessName = StringUtil.substring(tableName, lastIndex + 1, nameLength);
        return businessName;
    }

    public static String replaceKeyword(String keyword) {
        if (StringUtil.isEmpty(keyword)) {
            return "";
        }
        String keyName = keyword.replaceAll("(?:表|信息)", "");
        return keyName;
    }

    /**
     * 获取文件名
     */
    public static String getFileName(String template, String className, String packageName, String moduleName) {
        String packagePath = "main" + File.separator + "java" + File.separator;
        if (StringUtil.isNotBlank(packageName)) {
            packagePath += packageName.replace(".", File.separator) + File.separator;
        }

        if (template.contains("Persistence.java.vm")) {
            return packagePath  + moduleName + File.separator + "api" + File.separator + "model" + File.separator + className + ".java";
        }

        if (template.contains("Repository.java.vm")) {
            return packagePath + moduleName + File.separator + "repository" + File.separator + className + "Repository.java";
        }

        if (template.contains("RepositoryImpl.java.vm")) {
            return packagePath + moduleName + File.separator + "repository" + File.separator + "impl" + File.separator + className + "RepositoryImpl.java";
        }

        if (template.contains("Service.java.vm")) {
            return packagePath + moduleName + File.separator + "service" + File.separator + className + "Service.java";
        }

        if (template.contains("Controller.java.vm")) {
            return packagePath + moduleName + File.separator + "controller" + File.separator + className + "Controller.java";
        }

        if (template.contains("edit.html.vm")) {
            return "main" + File.separator + "resources" + File.separator + "templates" + File.separator
                    + moduleName + File.separator + className.toLowerCase() + File.separator + "edit.html";
        }

        if (template.contains("index.html.vm")) {
            return "main" + File.separator + "resources" + File.separator + "templates" + File.separator
                    + moduleName + File.separator + className.toLowerCase() + File.separator + "index.html";
        }

        if (template.contains("tree.html.vm")) {
            return "main" + File.separator + "resources" + File.separator + "templates" + File.separator
                    + moduleName + File.separator + className.toLowerCase() + File.separator + "tree.html";
        }

        if (template.contains("tree-table.html.vm")) {
            return "main" + File.separator + "resources" + File.separator + "templates" + File.separator
                    + moduleName + File.separator + className.toLowerCase() + File.separator + "tree-table.html";
        }

        if (template.contains("index.vue.vm")) {
            return "src" + File.separator + "views" + File.separator + moduleName + File.separator + className.toLowerCase() + File.separator + "index.vue";
        }

        if (template.contains("form.vue.vm")) {
            return "src" + File.separator + "views" + File.separator + moduleName + File.separator + className.toLowerCase() + File.separator + "form" + File.separator + "dialog.vue";
        }

        if (template.contains("treetable.vue.vm")) {
            return "src" + File.separator + "views" + File.separator + moduleName  + File.separator + className.toLowerCase()+ File.separator + "index.vue";
        }

        if (template.contains("tree.vue.vm")) {
            return "src" + File.separator + "views" + File.separator + moduleName + File.separator + className.toLowerCase() + File.separator + "tree" + File.separator + "dialog.vue";
        }
        return null;
    }

    public static Map<String, String> generatorJson(String sourceType, String className, String packageName, String jsonSchema) throws Exception {
        return generatorJson(sourceType, className, packageName, jsonSchema, true, false, false, true);
    }

    public static Map<String, String> generatorJson(String sourceType, String className, String packageName, String jsonSchema, boolean lombokAnnotationFlag, boolean jpaAnnotationFlag, boolean mybatisPlusAnnotationFlag, boolean swaggerAnnotationFlag) throws Exception {
        JCodeModel codeModel = new JCodeModel();
        JsonSchemaGeneratorConfig config = new JsonSchemaGeneratorConfig();
        if ("json".equalsIgnoreCase(sourceType)) {
            config.setSourceType(SourceType.JSON);
        } else {
            config.setSourceType(SourceType.JSONSCHEMA);
        }

        //1. 生成配置设置
        DefaultTypeInfoAnnotator annotator = new DefaultTypeInfoAnnotator(config);
        annotator.setJacksonAnnotationFlag(true);
        annotator.setLombokAnnotationFlag(lombokAnnotationFlag);
        annotator.setJpaAnnotationFlag(jpaAnnotationFlag);
        annotator.setMybatisPlusAnnotationFlag(mybatisPlusAnnotationFlag);
        annotator.setSwaggerAnnotationFlag(swaggerAnnotationFlag);
        SchemaMapper mapper = new SchemaMapper(new RuleFactory(config, annotator, new SchemaStore()), new SchemaGenerator());
        mapper.generate(codeModel, className, packageName, jsonSchema);
        //2. 开始生成代码
        PrintCodeWriter codeWriter = new PrintCodeWriter();
        codeModel.build(codeWriter);
        //3. 获取结果
        return codeWriter.contents();
    }
}
